package org.JWCB.friend.service.user;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.JWCB.common.core.constants.CacheConstants;
import org.JWCB.common.core.constants.UserConstants;
import org.JWCB.common.core.domain.vo.TableDataInfo;
import org.JWCB.common.core.enums.ExamListType;
import org.JWCB.common.core.enums.ResultCode;
import org.JWCB.common.core.exception.ServiceException;
import org.JWCB.common.core.utils.ThreadLocalUtil;
import org.JWCB.common.redis.service.RedisService;
import org.JWCB.common.security.service.TokenService;
import org.JWCB.friend.aspect.CheckUserStatus;
import org.JWCB.friend.domain.exam.dto.ExamQueryDto;
import org.JWCB.friend.domain.exam.entity.Exam;
import org.JWCB.friend.domain.exam.vo.ExamListItemVo;
import org.JWCB.friend.domain.user.dto.ExamSignUpDto;
import org.JWCB.friend.domain.user.entity.UserExam;
import org.JWCB.friend.manager.ExamCacheManager;
import org.JWCB.friend.mapper.exam.ExamMapper;
import org.JWCB.friend.mapper.user.UserExamMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;

@Service
public class UserExamService {

    @Autowired
    private UserExamMapper userExamMapper;


    @Autowired
    private ExamMapper examMapper;


    @Autowired
    private TokenService tokenService;

    @Autowired
    private ExamCacheManager examCacheManager;

    @Value("${jwt.secret}")
    private String secret;


    /**
     * 用户报名竞赛
     */
    @CheckUserStatus
    public int signUp(ExamSignUpDto examSignUpDto) {
        Exam exam = getExamById(examSignUpDto.getExamId());
        checkExam(exam);
        Long userId = ThreadLocalUtil.get(UserConstants.USER_ID,Long.class);
        UserExam userExam = userExamMapper.selectOne(new LambdaQueryWrapper<UserExam>()
                .eq(UserExam::getUserId,userId)
                .eq(UserExam::getExamId,examSignUpDto.getExamId()));
        if(userExam != null) {
            throw new ServiceException(ResultCode.USER_HAS_SIGNED_UP_EXAM);
        }
        userExam = new UserExam();
        userExam.setUserId(userId);
        userExam.setExamId(examSignUpDto.getExamId());
        int res = userExamMapper.insert(userExam);
        // 存入redis
        examCacheManager.addUserExamCache(userId,examSignUpDto.getExamId());
        return res;
    }

    /**
     * 根据examId得到exam
     */
    private Exam getExamById(Long examId) {
        Exam exam = examMapper.selectById(examId);
        if(exam == null) {
            throw new ServiceException(ResultCode.FAILED_NOT_EXISTS);
        }
        return exam;
    }


    /**
     * 对竞赛的操作进行校验
     */
    private void checkExam(Exam exam) {
        checkExamStarted(exam);
        checkExamEnded(exam);
    }

    /**
     * 判定竞赛是否已经开始
     */
    private void checkExamStarted(Exam exam) {
        if(exam.getStartTime().isBefore(LocalDateTime.now())) {
            throw new ServiceException(ResultCode.EXAM_HAVE_STARTED);
        }
    }

    /**
     * 判定竞赛是否已经结束
     */
    private void checkExamEnded(Exam exam) {
        if(exam.getEndTime().isBefore(LocalDateTime.now())) {
            throw new ServiceException(ResultCode.EXAM_HAVE_END);
        }
    }


    /**
     * 获取我的竞赛列表
     * @param queryDto 查询条件
     */
    public TableDataInfo list(ExamQueryDto queryDto) {
        Long userId = ThreadLocalUtil.get(UserConstants.USER_ID,Long.class);
        Long listSize = examCacheManager.getListSize(ExamListType.USER_EXAM_LIST.getValue(),userId);
        List<ExamListItemVo> examListItemVos = null;
        if(listSize == null || listSize == 0) {
            // 从数据库获取并刷新redis缓存
            PageHelper.startPage(queryDto.getPageNum(),queryDto.getPageSize());
            examListItemVos = userExamMapper.selectUserExamList(userId);
            examCacheManager.refreshCache(ExamListType.USER_EXAM_LIST.getValue(),userId);
            listSize = new PageInfo<>(examListItemVos).getTotal();
        }else {
            // 从缓存中获取
            queryDto.setType(ExamListType.USER_EXAM_LIST.getValue());
            examListItemVos = examCacheManager.getExamList(queryDto,userId);
            listSize = examCacheManager.getListSize(ExamListType.USER_EXAM_LIST.getValue(),userId);
        }
        if(CollectionUtil.isEmpty(examListItemVos)) {
            return TableDataInfo.empty();
        }
        return TableDataInfo.success(examListItemVos,listSize);
    }
}
